<?php

namespace app\home\controller;

use app\common\controller\Home;
use think\Request;


class Subject extends Home
{
    // 先写所以方法都不要登录
    public $NoLogin = ['info','index','likes','play'];

    public function __construct()
    {
        // 继承公共控制器
        parent::__construct();

        $this->SubjectModel = model('Subject.Subject');
        /* 加载TeachetModel。为下面对数据库里面的fa_subject_teacher的name字段和job字段做模糊查询做准备。换句话说，想在那个数据库操作，
        必须先得拿到这个数据库*/
        $this->TeacherModel = model('Teacher.Teacher');
        $this->CategoryModel = model('Subject.Category');
        $this->ChapterModel = model('Subject.Chapter');
        $this->CommentModel = model('Subject.Comment');
        $this->CollectionModel = model('Subject.Collection');
        $this->SubjectModel = model('Subject.Subject');
        $this->OrderModel = model('Subject.Order');
        $this->ReceiveModel = model('Coupon.Receive');
        $this->RecordModel = model('Business.Record');
        $this->BusinessModel = model('Business.Business');
        $this->CommissionModel = model('Business.Commission');





    }

        // 课程搜索
    public function index()
    {
         //接收ajax请求
        if($this->request->isAjax())
        {
            // 有就拿，没有就分别给1，10，''
            $page = $this->request->param('page',1,'trim');
            $limit = $this->request->param('limit',10,'trim'); //limit为每页显示多少条,
            $keywords = $this->request->param('keywords','','trim');

            // 偏移量。为下面每页查询多少条准备
            $start = ($page-1)*$limit;

            // 符合条件是关键词不为空,组装条件去查询，就去做模糊查询
            $where = []; 
            if(!empty($keywords))
            {
                // 对课程表中的title字段,做模糊查询
                $where['title'] = ['LIKE',"%$keywords%"];
            }

            // 模糊查询完，会返回一个总条数，这时再做一个查询
            $count = $this->SubjectModel->where($where)->count();

            // 查询数据。limit($start,$limit)表示从哪里开始查，查多少条，$start就是上面定义的偏移量
            $list = $this->SubjectModel
                    /* 'category'和'teacher'是连表查询的两个方法。因为数据库老师表fa_subject_teacher中有外键id，
                    cateid和teacherid,分别为课程分类的外键和关联老师的外键，所以这里没有连表查询存在连表查询，
                    分别为分类查询和关联查询，构造的地方在模型application/common/model/Subject.php */
                    ->with(['category','teacher'])
                    ->where($where)
                    ->limit($start,$limit)
                    ->select();
            
            // 组装数据 ，在查询完数据后进行
            $data = [
                'count' => $count,
                'list' => $list
            ];

            // 接下来，把打印所看到的结果，从哪里发送过来就扔回去哪里。
            // 但是扔回去之前也要做一个条件判断，以确保扔回去的是正确的结果

            // 判断是否成功返回
            if($list)
            {
               //成功返回
               $this->success('返回列表',null,$data); 
               exit;
            }else
            {
                //返回失败
                $this->error('暂无数据',null,$data);
                exit; 
            }

            /* 到这里ajax的返回值就已经有了，这时回到发送过来的地方fast/application/home/view/index/subject.html，里面的console.log(result)
            把结果作为返回值给到它*/

            // 一个问题：在讲邮件发送时讲过，这两个方法会根据语境自动转换：如果正常请求，会跳转;如果是Ajax请求，会自动返回json结果

        }

        return $this->view->fetch();
    }



    //课程详情页面
    public function info()
    {
        // 接收课程的id
        $subid = $this->request->param('subid', 0, 'trim');
 
        $subject = $this->SubjectModel->with(['category'])->find($subid);

        // 如果课程不存在，就在这里停掉，不再往下查询
        if(!$subject)
        {
            $this->error('课程不存在');
            exit;
        }

         //（点赞）给点赞状态设置一个属性嵌入到课程资料中。这里先默认是false,如果下面if($login)判断出来是点赞过，会把这个名字相同的覆盖掉
        $subject['likes_active'] = false;

        //获取登录信息
        $login = $this->IsLogin(false);


        // 判断是否已购买课程
        // 默认情况下时未购买
        $buy = false; 

        // （点赞）判断是否有点过赞。点过赞就进来详情页图标是红色的
         if($login)
        {
            // 从点赞的方法那里拿到，判断是否有点赞这个字段
            $likes = isset($subject['likes']) ? trim($subject['likes']) : '';
            // 通过 explode(',', $likes) 函数将 $likes 变量按照逗号 , 为分隔符，分割成一个数组，并将数组赋值给 $likes 变量。
            $likes = explode(',', $likes);

            //增加一个自定义属性
            $subject['likes_active'] = in_array($login['id'], $likes) ? true : false;

            
             $where = ['subid' => $subid, 'busid' => $login['id']];// 查询当前用户是否有购买过
            $check = $this->OrderModel->where($where)->find();
            // 这个$buy变量，传到课程的详情页的，做条件判断
            $buy = $check ? true : false;

        }

         //查询章节
        $chapter = $this->ChapterModel->where(['subid' => $subid])->select();

        // 查询评论
        $comment = $this->CommentModel->where(['subid' => $subid])->select();

        //老师信息。先判断是否存在，这个课程下老师外键teacherid是否存在。再来查询老师
        $teacherid = isset($subject['teacherid']) ? trim($subject['teacherid']) : 0;
        $teacher = $this->TeacherModel->find($teacherid);

        // 接收post（ajax异步）发送请求，来自fast/application/home/view/index/subject.html
        if($this->request->isAjax())
        {
            // 有就拿，没有就分别给1，10，''
            $page = $this->request->param('page',1,'trim');
            $limit = $this->request->param('limit',10,'trim'); //limit为每页显示多少条,
            $keywords = $this->request->param('keywords','','trim');

            // 偏移量。为下面每页查询多少条准备
            $start = ($page-1)*$limit;

            // 条件是在fa_subject_是查找,组装条件去查询，就去做模糊查询
            $where = ['subid' => $subid]; 
            
            if(!empty($keywords))
            {
                // 对课程表中的content字段,做模糊查询
                $where['content'] = ['LIKE',"%$keywords%"];
            }

            // 连表查询，连表查询的方法business()，方法存放的地方application/common/model/Subject/Comment.php
            // 注意这里加了with()语句，下面也要加
            $count = $this->CommentModel->with('business')->where($where)->count();

            // 查询数据。limit($start,$limit)表示从哪里开始查，查多少条，$start就是上面定义的偏移量
            $list = $this->CommentModel
                    ->with(['business'])
                    ->where($where)
                    ->order('id desc') //按id进行降序
                    ->limit($start,$limit)
                    ->select();
            
            // 组装数据 ，在查询完数据后进行
            $data = [
                'count' => $count,
                'list' => $list
            ];

            // 接下来，把打印所看到的结果，从哪里发送过来就扔回去哪里。
            // 但是扔回去之前也要做一个条件判断，以确保扔回去的是正确的结果



            // 判断是否成功返回
            if($list)
            {
               //成功返回
               $this->success('返回列表',null,$data); 
               exit;
            }else
            {
                //返回失败
                $this->error('暂无数据',null,$data);
                exit; 
            }

            /* 到这里ajax的返回值就已经有了，这时回到发送过来的地方fast/application/home/view/index/subject.html，里面的console.log(result)
            把结果作为返回值给到它*/

            // 一个问题：在讲邮件发送时讲过，这两个方法会根据语境自动转换：如果正常请求，会跳转;如果是Ajax请求，会自动返回json结果

        }

        // 到这里就拿到了三个基本信息

        // 拿到信息后，就赋值
        $this->assign([
            'subject' => $subject,
            'chapter' => $chapter,
            'teacher' => $teacher,
            'buy' =>$buy,
        ]);







        
        return $this->view->fetch();


    }



    //课程点赞
    public function likes()
    {
        if($this->request->isAjax())
        {
            $subid = $this->request->param('subid', 0, 'trim');

            $subject = $this->SubjectModel->find($subid);

            // var_dump($subject->toArray());
            // die;

            // 判断课程是否存在
            if(!$subject)
            {
                $this->error('课程不存在');
                exit;
            }

            //判断是否有登录
            $login = $this->IsLogin(false);

            if(!$login)
            {
                $this->error('请先登录');
                exit;
            }

            // 判断是否有点赞这个字段,是一个字符串，可以打印为数组
            $likes = isset($subject['likes']) ? trim($subject['likes']) : '';  
            
            // 通过 explode(',', $likes) 函数将 $likes 变量按照逗号 , 为分隔符，分割成一个数组，并将数组赋值给 $likes 变量。
            $likes = explode(',', $likes);    
            
            $action = $msg = '';
            
            //如果用户ID在数组中就说明点过赞,不在就说明没有点赞
            // var_dump(in_array($login['id'], $likes));
            // exit;

            
            


            // 点赞后，需要取消点赞，走到这里

            
            /* in_array($login['id'], $likes)这段代码是 PHP 语言中的一行，用于判断数组 $likes 中是否包含变量 $login['id'] 的值。

            in_array 函数用于检查一个值是否在数组中，它的第一个参数是要查找的值，第二个参数是要查找的数组。如果找到该值，in_array 函数将返回 true，否则返回 false。

            在这段代码中，$login['id'] 是一个数组键 'id' 对应的值，而 $likes 是一个数组。因此，这段代码的作用是判断 $likes 数组中是否包含 $login['id'] 的值。

            需要注意的是，如果 $likes 数组中包含的值是数字，而 $login['id'] 的值是字符串，那么这段代码可能会返回错误的结果。这是因为 PHP 在比较数字和字符串时会将字符串转
            
            换为数字，从而可能导致比较失败。因此，在使用这段代码时需要注意数组中元素的数据类型*/
            if(in_array($login['id'], $likes))
            {
                //寻找数组元素。   array_search()方法的作用，php数组中找到指定元素的下标。第一个要找的是元素
                $key = array_search($login['id'], $likes);
                    /* 在PHP中，array_search函数用于在一个数组中查找指定值的键。这段代码的意思是：
                    $login['id']：假设$login是一个关联数组，其中包含一个名为id的元素，$login['id']获取这个元素的值。
                    $likes：这是一个数组，$likes中的元素可能是关联数组的键，或者是整数索引。
                    $key = array_search($login['id'], $likes);这行代码的作用是查找$likes数组中，值与$login['id']相匹配的键。
                    如果找到，$key将存储对应的数组键；如果没找到，$key将返回false。
                    如果$login['id']在$likes数组中存在，$key将是一个整数，表示元素在数组中的位置（从0开始）。如果$login['id']不存在，$key将为false。*/

                //删除数组元素
                unset($likes[$key]);

                //取消动作
                $action = 'cancel';
                $msg = '取消点赞';
            }else
            {
                //他没有点过赞，现在要点赞
                $likes[] = $login['id'];
                
                $action = 'active';
                $msg = '点赞';
            }




            /*array_filter($likes) 函数用于过滤数组中的值。它接收一个数组作为参数，并通过一个回调函数来判断数组中的每个元素是否应该被保留。如果回调函数返回 true，

            则该元素会被保留在数组中；如果返回 false，则该元素会被丢弃。在这个例子中，$likes 数组中的每个元素都会被传递给 array_filter 函数，如果元素不是空或者 false，

            则它会被保留在数组中。

            array_unique($likes) 函数用于去除数组中重复的值。它接收一个数组作为参数，并返回一个新的数组，该数组包含原数组中唯一的值。在这个例子中，$likes 数组中的重复值

            都会被去除，只保留唯一的值。

            综上所述，这两行代码的作用是过滤和去重 $likes 数组中的值，只保留唯一的、非空的值。*/

            // 去空
            $likes = array_filter($likes);
            // 去唯一
            $likes = array_unique($likes);

            // 组装数据
            $data = [
                'id' => $subid,
                'likes' => implode(',', $likes)
            ];

            //更新语句
            $result = $this->SubjectModel->isUpdate(true)->save($data);

            // 判断有无更新失败
            if($result === FALSE)
            {
                $this->error("{$msg}失败");
                exit;
            }else
            {
                $this->success("{$msg}成功", null, ['action' => $action]);
                exit;
            }
        }
    }



    // 课程收藏
    public function collection(){
        if($this->request->isAjax()){

            $subid = $this->request->param('subid',0,'trim');

            $subject = $this->SubjectModel->find($subid);

            // 判断课程是否存在
            if(!$subject)
            {
                $this->error('课程不存在');
                exit;
            }

            //判断是否有登录
            $login = $this->IsLogin(false);

            if(!$login)
            {
                $this->error('请先登录');
                exit;
            }

            // $action = $msg = '';

            
             $where = [
            'subid' => $subid,
            'busid' => $this->view->AutoLogin['id']
            ];

            // 在收藏表查找, 判断是否有收藏这个字段
            $check = $this->CollectionModel->where($where)->find();

            // 如果查到这个字段就给赋值给$collection；如果没有就给空
            $collection = isset($check['id']) ? trim($check['id']) : '';

            // 通过 explode(',', $collection) 函数将 $collection 变量按照逗号 , 为分隔符，分割成一个数组，并将数组赋值给 $collection 变量。
            $collection = explode(',', $collection);
        
            

            if($collection)
            {
                // 删除语句
                // 判断是否删除成功，并且提醒

            }else
            {
                // 插入语句
                // 判断是否插入成功，并且提醒
            }


            



            // if($check)
            // {
            //     $this->error('已领取过该优惠券，不能重复领取');
            //     exit;
            // }

            // //收藏后，需要取消收藏，走到这里
            // if(in_array($login['id'], $collection))
            // {

            //     //寻找数组元素。   array_search()方法的作用，php数组中找到指定元素的下标
            //     $key = array_search($login['id'], $collection);

            //     //删除数组元素
            //     unset($collection[$key]);

            //     //取消动作
            //     $action = 'cancel';
            //     $msg = '取消收藏';
            // }else
            // {
            //     //他没有点收藏，现在要收藏
            //     $likes[] = $login['id'];
                
            //     $action = 'active';
            //     $msg = '收藏';
            // }





            //  var_dump($subject->toArray());
            // die;


        }
        //  return $this->view-fetch();
    }



    // 课程购买
    public function confirm()
    {
        // $AmountRate = config('site.AmountRate');
        // var_dump($AmountRate);
        // die;
       
        $subid = $this->request->param('subid', 0, 'trim');

        //查询一下课程是否存在。
        // 因为要在课程购买界面示授课老师和课程分类，所以要做这两个的连表查询，with()语句里面就是连表查询的两个方法
        $subject = $this->SubjectModel->with(['category', 'teacher'])->find($subid);


        if(!$subject)
        {
            $this->error('课程不存在');
            exit;
        }



        $where = [
            'busid' => $this->view->AutoLogin['id'],
            
            // 表fa_business_receive中的cid表示优惠券的外键id，当状态status=1时，才可以使用
            // 领取表fa_business_receive和连表查询中的表fa_coupon都各自有个status字段，所以要在status字段前说明是哪个表
            'receive.status' => '1'
        ];

        // 查询当前这个人领取过而且目前可以使用的优惠券。所以做一个连表查询，方法在model/Receive.php/coupon()
        $coupon = $this->ReceiveModel->with(['coupon'])->where($where)->select();

        
        // var_dump(collection($coupon)->toArray());
        // exit;
     
        // 接收传过来的数据，有优惠券和支付方式
         if($this->request->isPost())
        {
            $couid = $this->request->param('coupon', 0, 'trim');
            $pay = $this->request->param('pay', 'money', 'trim');
            $total = isset($subject['price']) ? trim($subject['price']) : 0;

            // var_dump($couid,$pay);
            // die; 

            // 立即支付，一共操作四张表
            // subject_order 用户订单表
            // business_record 用户消费记录
            // business 用户表
            // coupon_receive 优惠券领取记录表

            // 开启以下这些表的事务
            $this->OrderModel->startTrans();
            $this->RecordModel->startTrans();
            $this->BusinessModel->startTrans();
            $this->ReceiveModel->startTrans();
            $this->CommissionModel->startTrans();

            //查询是否有选择优惠券
            $where = ['receive.id' => $couid, 'receive.status' => '1'];
            $coupon = $this->ReceiveModel->with(['coupon'])->where($where)->find();

            // var_dump($coupon);
            // exit;
  
            // 如果有查到优惠券
            if($coupon)
            {
                //获取到折扣率
                $rate = isset($coupon['coupon']['rate']) ? trim($coupon['coupon']['rate']) : 1;
                
                //两个高精度数字相乘
                $total = bcmul($total, $rate);
            }

             //插入订单表
            $OrderData = [
                'subid' => $subid,
                'busid' => $this->view->AutoLogin['id'],
                'pay' => $pay,
                'total' => $total,
                // 这个如何获取，是直接在公共模块里面某个
                'code' => build_code("ST"),
            ];
        
            //插入到订单表
            $OrderStatus = $this->OrderModel->validate('common/Subject/Order')->save($OrderData);

            //（第一张表） 如果插入订单表失败，拦截并提醒
            if($OrderStatus === FALSE)
            {
                $this->error($this->OrderModel->getError());
                exit;
            }

             //消费记录
            $title = $subject['title'];
            $content = "购买了【{$title}】,花费了￥ $total 元";
            $RecordData = [
                'total' => "-$total",
                'content' => $content,
                'busid' => $this->view->AutoLogin['id']
            ];


            //把数据插入购买记录表中
            $RecordStatus = $this->RecordModel->validate('common/Business/Record')->save($RecordData);

             //（第二张表）消费记录
            if($RecordStatus === FALSE)
            {
                $this->OrderModel->rollback();
                $this->error($this->RecordModel->rollback());
                exit;
            }

            //如果是余额支付就需要更新用户余额字段
            if($pay == "money")
            {
                //余额支付。减去消费的金额 剩下的余额。bcsub（） 函数用于执行两个任意精度数的减法运算。
                $money = bcsub($this->view->AutoLogin['money'], $total);

                // 组装数据，给到数组$BusinessData
                $BusinessData = [
                    'id' => $this->view->AutoLogin['id'],
                    'money' => $money
                ];

                // 组装好的数组出入数据库中
                $BusinessStatus = $this->BusinessModel->isUpdate(true)->save($BusinessData);


                //（第三张表） 如果插入购买记录表中失败，就前面的两表都做回滚
                if($BusinessStatus === FALSE)
                {
                    $this->RecordModel->rollback();
                    $this->OrderModel->rollback();
                    $this->error('个人余额更新失败');
                    exit;
                }
            }


            //优惠券判断。如果有选择优惠券那么就要更新优惠券使用状态
            if($coupon)
            {
                $ReceiveData = [
                    'id' => $couid,
                    'status' => '0'
                ];

                // 更新数据表
                $ReceiveStatus = $this->ReceiveModel->isUpdate(true)->save($ReceiveData);

                // （第四张表）
                if($ReceiveStatus === FALSE)
                {
                    $this->BusinessModel->rollback();
                    $this->RecordModel->rollback();
                    $this->OrderModel->rollback();
                    $this->error('优惠券状态更新失败');
                    exit;
                }
            }

            
            //判断是否有推荐人可以得到佣金
            $parentid = $this->view->AutoLogin['parentid'] ? trim($this->view->AutoLogin['parentid']) : 0;
            $parent = $this->BusinessModel->find($parentid);

            // 佣金判断。
            if($parent)
            {   
                
                //佣金比率。
                //拿到购买课程的佣金比例。在后台的建立佣金比例的右边拿到，复制来这里
                $AmountRate = config('site.AmountRate');
                
               

                //消费金额*佣金比率 = 转给推荐人
                $amount = bcmul($total, $AmountRate);

                

                //插入佣金记录
                $CommissionData = [
                    'orderid' => $this->OrderModel->id, //获取插入最后一条的自增ID
                    'busid' => $this->view->AutoLogin['id'],
                    'parentid' => $parentid, //上级id
                    'type' => 'subject', //买课程的佣金
                    'stauts' => '0', //未提现
                    'amount' => $amount, //佣金。
                    
                ];

                // 插入佣金记录
                $CommissionStatus = $this->CommissionModel->save($CommissionData);

                if($CommissionStatus === FALSE)
                {
                    $this->ReceiveModel->rollback();
                    $this->BusinessModel->rollback();
                    $this->RecordModel->rollback();
                    $this->OrderModel->rollback();
                    $this->error('推荐信息存储失败');
                    exit;
                }


            }
            
            // 做一个总的判断，只需要判断两个主线的状态。回滚一定一定要反向操作 
            if($OrderStatus === FALSE || $RecordStatus === FALSE)
            {
                $this->CommissionModel->rollback();
                $this->ReceiveModel->rollback();
                $this->BusinessModel->rollback();
                $this->RecordModel->rollback();
                $this->OrderModel->rollback();
                $this->error('推荐信息存储失败');
                exit;
            }else
            {
                $this->OrderModel->commit();
                $this->RecordModel->commit();
                $this->BusinessModel->commit();
                $this->ReceiveModel->commit();
                $this->CommissionModel->commit();
                $this->success('购买课程成功', url('home/subject/info', ['subid' => $subid]));
                exit;
            }

        }



         $this->assign([
            'subject' => $subject,
            // 通过json_encode()，把$coupon从数组转化为字符串，传过去才可以打印出来
            'coupon' => json_encode($coupon)
        ]);

        return $this->view->fetch();
    } 
   


    // 课程播放
    public function play()
    {
        if($this->request->isAjax())
        {
            $cid = $this->request->param('cid',0,'trim');

            // 查询一下这个章节是否存在
            $chapter = $this->ChapterModel->find($cid);

            if(!$chapter)
            {
                $this->error('章节不存在');
                exit;
            }

            //判断是否有登录
            $login = $this->IsLogin(false);

            if(!$login)
            {
                $this->error('请先登录');
                exit;
            }

             //查找当前用户是否购买过订单
            $where = [
                'subid' => $chapter['subid'],
                'busid' => $login['id']
            ]; 

            // 查询是否有这条语句
            $order = $this->OrderModel->where($where)->find();

            if(!$order)
            {
                /* 没有买课，提醒先买课程，*/
                $this->error('请先购买课程');
                exit;
            }

            $this->success('返回章节的信息', null,  $chapter['url_text']);
            exit;
        } 
    }


    
}
